grammar Olive3;

options {
  output=AST;
  ASTLabelType = CommonTree;
}

tokens {
  KeyVal;
  Message;
  OliveStream;
  Optional;
  Params;
  Required;
  Statement;
  Statements;
}

@header {
package org.six11.olive3.net;

import java.util.Map;
}

@members {
  Map<String, String> params;
  
  public void setParams(Map<String, String> params) {
    this.params = params;
  }
}

@lexer::header {
package org.six11.olive3.net;
}



olive_stream
	:	block*
		-> ^(OliveStream block*)
	;
	
block
	:	ID assignments '{' statements '}'
		-> ^(Message ID assignments statements)
	;

assignments
	:	'(' assignment* ')'
		-> ^(Params assignment*)
	;

assignment
	:	ID '=' literal
		-> ^(KeyVal ID literal)
	;

statements
	:	statement*
		-> ^(Statements statement*)
	;
	
statement
	:	type=ID required+=literal* optional+=assignment*
		-> ^(Statement $type ^(Required $required*) ^(Optional $optional*))
	;
	
literal	
    	:	literalNum
    	|	literalString
	;

literalNum
	:	NUM
	;

literalString
	:	STR_CHARS
	;

NUM	:	INT+
	|	INT* '.' INT+
	;
	
ID	:	(LETTER | '_') (LETTER | '_' | INT)*
	;

fragment
LETTER	:	('a'..'z'|'A'..'Z')
	;

fragment			
INT	:	('0'..'9')+
    	;
    	

STR_CHARS
	:	'"' ( ESC_SEQ | ~('\\'|'"') )* '"'
	;
	
fragment
ESC_SEQ
    	:	'\\' ('b'|'t'|'n'|'f'|'r'|'\"'|'\''|'\\')
    	|	UNI_ESC
    	|	OCT_ESC
	;

fragment
OCT_ESC	:	'\\' ('0'..'3') ('0'..'7') ('0'..'7')
	|	'\\' ('0'..'7') ('0'..'7')
	|	'\\' ('0'..'7')
	;

fragment
UNI_ESC	:	'\\' 'u' HEX_DIGIT HEX_DIGIT HEX_DIGIT HEX_DIGIT
    	;

fragment
HEX_DIGIT
	:	('0'..'9'|'a'..'f'|'A'..'F') 
	;

WS	:	(' ' | '\t' ) { $channel = HIDDEN; }
	;

NL	:	'\r'? '\n' { $channel = HIDDEN; }
	;
